home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / system-config-printer / GroupsPane.py < prev    next >
Text File  |  2009-10-19  |  16KB  |  418 lines

  1. ## Copyright (C) 2008 Rui Matos <tiagomatos@gmail.com>
  2.  
  3. ## This program is free software; you can redistribute it and/or modify
  4. ## it under the terms of the GNU General Public License as published by
  5. ## the Free Software Foundation; either version 2 of the License, or
  6. ## (at your option) any later version.
  7.  
  8. ## This program is distributed in the hope that it will be useful,
  9. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. ## GNU General Public License for more details.
  12.  
  13. ## You should have received a copy of the GNU General Public License
  14. ## along with this program; if not, write to the Free Software
  15. ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  
  17. import gtk
  18. import gobject
  19. from gettext import gettext as _
  20.  
  21. from GroupsPaneModel import *
  22. from XmlHelper import xml_helper
  23.  
  24. class GroupsPane (gtk.ScrolledWindow):
  25.     __gsignals__ = {
  26.         'item-activated' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
  27.                             [GroupsPaneItem]),
  28.         'items-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
  29.                            []),
  30.         }
  31.  
  32.     def __init__ (self):
  33.         super (GroupsPane, self).__init__ ()
  34.  
  35.         self.tree_view = None
  36.         self.store = None
  37.         self.groups_menu = None
  38.         self.ui_manager = None
  39.         self.currently_selected_queues = []
  40.  
  41.         self.set_policy (gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
  42.  
  43.         self.tree_view = gtk.TreeView ()
  44.         self.tree_view.set_headers_visible (False)
  45.  
  46.         column = gtk.TreeViewColumn ()
  47.  
  48.         cell = gtk.CellRendererPixbuf ()
  49.         column.pack_start (cell, False)
  50.         column.set_cell_data_func (cell, self.icon_cell_data_func)
  51.  
  52.         cell = gtk.CellRendererText ()
  53.         column.pack_start (cell, True)
  54.         column.set_cell_data_func (cell, self.label_cell_data_func)
  55.  
  56.         # To change the group name in place
  57.         cell.connect ('edited', self.on_group_name_edited)
  58.         cell.connect ('editing-canceled', self.on_group_name_editing_canceled)
  59.  
  60.         self.tree_view.set_row_separator_func (self.row_separator_func)
  61.         self.tree_view.append_column (column)
  62.  
  63.         self.store = GroupsPaneModel ()
  64.         self.tree_view.set_model (self.store)
  65.  
  66.         self.add (self.tree_view)
  67.         self.show_all ()
  68.  
  69.         self.tree_view.connect ('key-press-event',
  70.                                 self.on_key_press_event)
  71.         self.tree_view.connect ('button-press-event',
  72.                                 self.on_button_press_event)
  73.         self.tree_view.connect ('button-press-event',
  74.                                 self.on_single_click_activate)
  75.         self.tree_view.connect ('row-activated',
  76.                                 self.on_row_activated)
  77.         self.tree_view.connect ('popup-menu',
  78.                                 self.on_popup_menu)
  79.  
  80.         self.tree_view.enable_model_drag_dest ([("queue", 0, 0)],
  81.                                                gtk.gdk.ACTION_COPY)
  82.         self.tree_view.connect ("drag-data-received",
  83.                                 self.on_drag_data_received)
  84.         self.tree_view.connect ("drag-drop",
  85.                                 self.on_drag_drop)
  86.         self.tree_view.connect ("drag-motion",
  87.                                 self.on_drag_motion)
  88.  
  89.         # actions
  90.         action_group = gtk.ActionGroup ("GroupsPaneActionGroup")
  91.         action_group.add_actions ([
  92.                 ("new-group", gtk.STOCK_NEW, _("_New Group"),
  93.                  "<Ctrl>g", None, self.on_new_group_activate),
  94.                 ("new-group-from-selection", None,
  95.                  _("_New Group from Selection"),
  96.                  "<Ctrl><Shift>g", None,
  97.                  self.on_new_group_from_selection_activate),
  98.                 ("rename-group", None, _("_Rename"),
  99.                  None, None, self.on_rename_group_activate),
  100.                 ("delete-group", gtk.STOCK_DELETE, None,
  101.                  None, None, self.on_delete_group_activate),
  102.                 ])
  103.         action_group.get_action (
  104.             "new-group-from-selection").set_sensitive (False)
  105.         action_group.get_action (
  106.             "rename-group").set_sensitive (False)
  107.         action_group.get_action (
  108.             "delete-group").set_sensitive (False)
  109.  
  110.         self.ui_manager = gtk.UIManager ()
  111.         self.ui_manager.insert_action_group (action_group, -1)
  112.         self.ui_manager.add_ui_from_string (
  113. """
  114. <ui>
  115.  <accelerator action="new-group"/>
  116.  <accelerator action="new-group-from-selection"/>
  117.  <accelerator action="rename-group"/>
  118.  <accelerator action="delete-group"/>
  119. </ui>
  120. """
  121. )
  122.         self.ui_manager.ensure_update ()
  123.  
  124.         self.groups_menu = gtk.Menu ()
  125.         for action_name in ["new-group",
  126.                             "new-group-from-selection",
  127.                             None,
  128.                             "rename-group",
  129.                             "delete-group"]:
  130.             if not action_name:
  131.                 item = gtk.SeparatorMenuItem ()
  132.             else:
  133.                 action = action_group.get_action (action_name)
  134.                 item = action.create_menu_item ()
  135.             item.show ()
  136.             self.groups_menu.append (item)
  137.  
  138.         selection = self.tree_view.get_selection ()
  139.         selection.connect ("changed", self.on_selection_changed)
  140.         selection.set_mode (gtk.SELECTION_BROWSE)
  141.         selection.select_iter (self.store.append (AllPrintersItem ()))
  142. #        self.store.append (FavouritesItem ())
  143.         self.store.append (SeparatorItem ())
  144.         for group_name, group_node in xml_helper.get_static_groups ():
  145.             self.store.append (StaticGroupItem (group_name, group_node))
  146.         for group_name, group_node in xml_helper.get_search_groups ():
  147.             self.store.append (SavedSearchGroupItem (group_name,
  148.                                                      xml_node = group_node))
  149.  
  150.     def icon_cell_data_func (self, column, cell, model, iter):
  151.         icon = model.get (iter).icon
  152.         cell.set_properties (pixbuf = icon)
  153.  
  154.     def label_cell_data_func (self, column, cell, model, iter):
  155.         label = model.get (iter).name
  156.         cell.set_properties (text = label)
  157.  
  158.     def on_group_name_edited (self, cell, path, new_text):
  159.         cell.set_properties (editable = False)
  160.  
  161.         group_item = self.get_selected_item ()
  162.         if group_item.name == new_text:
  163.             return
  164.  
  165.         if self.store.lookup_by_name (new_text):
  166.             dialog = gtk.MessageDialog (self.get_toplevel (),
  167.                                         gtk.DIALOG_DESTROY_WITH_PARENT,
  168.                                         gtk.MESSAGE_ERROR,
  169.                                         gtk.BUTTONS_OK,
  170.                                         _("The item could not be renamed."))
  171.             dialog.format_secondary_text (_("The name \"%s\" is already "
  172.                                             "in use. Please use a different "
  173.                                             "name.") % new_text)
  174.             dialog.connect ('response', lambda dialog, x: dialog.destroy ())
  175.             dialog.show ()
  176.             return
  177.  
  178.         group_item.rename (new_text)
  179.         self.emit ("items-changed")
  180.  
  181.     def on_group_name_editing_canceled (self, cell):
  182.         cell.set_properties (editable = False)
  183.  
  184.     def on_key_press_event (self, tree_view, event):
  185.         modifiers = gtk.accelerator_get_default_mod_mask ()
  186.  
  187.         if ((event.keyval == gtk.keysyms.BackSpace or
  188.              event.keyval == gtk.keysyms.Delete or
  189.              event.keyval == gtk.keysyms.KP_Delete) and
  190.             ((event.state & modifiers) == 0)):
  191.  
  192.             self.delete_selected_group ()
  193.             return True
  194.  
  195.         if ((event.keyval == gtk.keysyms.F2) and
  196.             ((event.state & modifiers) == 0)):
  197.  
  198.             self.rename_selected_group ()
  199.             return True
  200.  
  201.         return False
  202.  
  203.     def on_single_click_activate (self, tree_view, event):
  204.         # idea from eel_gtk_tree_view_set_activate_on_single_click ()
  205.         if event.button == 1:
  206.             t = self.tree_view.get_path_at_pos (int (event.x),
  207.                                                 int (event.y))
  208.             if t != None:
  209.                 self.tree_view.row_activated (t[0], t[1])
  210.  
  211.         return False
  212.  
  213.     def on_row_activated (self, tree_view, path, column):
  214.         tree_view.get_selection ().select_path (path)
  215.         item = self.store.get (path)
  216.         self.emit ('item-activated', item)
  217.  
  218.     def on_selection_changed (self, selection):
  219.         model, titer = selection.get_selected ()
  220.         group_item = model.get (titer)
  221.         sensitivity = isinstance (group_item, MutableItem)
  222.         self.ui_manager.get_action ("/rename-group").set_sensitive (sensitivity)
  223.         self.ui_manager.get_action ("/delete-group").set_sensitive (sensitivity)
  224.  
  225.     def row_separator_func (self, model, iter):
  226.         return model.get (iter).separator
  227.  
  228.     def do_popup_menu (self, event):
  229.         # idea from eel_pop_up_context_menu ()
  230.         button = 0
  231.         activate_time = 0L # GDK_CURRENT_TIME
  232.         if event:
  233.             activate_time = event.time
  234.             if event.type != gtk.gdk.BUTTON_RELEASE:
  235.                 button = event.button
  236.  
  237.         self.groups_menu.popup (None, None, None, button, activate_time)
  238.  
  239.     def on_button_press_event (self, tree_view, event):
  240.         if event.button == 3:
  241.             selection = tree_view.get_selection ()
  242.             model, selected_paths = selection.get_selected_rows ()
  243.             click_info = tree_view.get_path_at_pos (int (event.x),
  244.                                                     int (event.y))
  245.             if click_info and (click_info[0] not in selected_paths):
  246.                 selection.select_path (click_info[0])
  247.  
  248.             self.do_popup_menu (event)
  249.  
  250.         return False
  251.  
  252.     def on_popup_menu (self, tree_view):
  253.         self.do_popup_menu (None)
  254.  
  255.         return True
  256.  
  257.     def on_rename_group_activate (self, UNUSED):
  258.         self.rename_selected_group ()
  259.  
  260.     def on_delete_group_activate (self, UNUSED):
  261.         self.delete_selected_group ()
  262.  
  263.     def rename_selected_group (self):
  264.         model, titer = self.tree_view.get_selection ().get_selected ()
  265.         group_item = model.get (titer)
  266.         if not isinstance (group_item, MutableItem):
  267.             return
  268.  
  269.         column = self.tree_view.get_column (0)
  270.         cell = None
  271.         for cr in column.get_cell_renderers ():
  272.             if isinstance (cr, gtk.CellRendererText):
  273.                 cell = cr
  274.                 break
  275.         cell.set_properties (editable = True)
  276.         self.tree_view.set_cursor_on_cell (model.get_path (titer),
  277.                                            column, cell, True)
  278.  
  279.     def delete_selected_group (self):
  280.         model, titer = self.tree_view.get_selection ().get_selected ()
  281.         group_item = model.get (titer)
  282.         if not isinstance (group_item, MutableItem):
  283.             return
  284.  
  285.         dialog = gtk.MessageDialog (self.get_toplevel (),
  286.                                     gtk.DIALOG_DESTROY_WITH_PARENT |
  287.                                     gtk.DIALOG_MODAL,
  288.                                     gtk.MESSAGE_WARNING,
  289.                                     gtk.BUTTONS_NONE,
  290.                                     _("Are you sure you want to "
  291.                                       "permanently delete \"%s\"?") %
  292.                                     group_item.name)
  293.         dialog.add_buttons (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
  294.                             gtk.STOCK_DELETE, gtk.RESPONSE_ACCEPT)
  295.         dialog.set_default_response (gtk.RESPONSE_REJECT)
  296.         dialog.format_secondary_text (_("This will not delete any printer queues from your computer. To delete queues completely, you must delete them from the 'All Printers' group."))
  297.         dialog.connect ('response', self.on_delete_selected_group_response,
  298.                         group_item, titer)
  299.         dialog.show ()
  300.  
  301.     def on_delete_selected_group_response (self, dialog, response,
  302.                                            group_item, titer):
  303.         dialog.destroy ()
  304.  
  305.         if response == gtk.RESPONSE_ACCEPT:
  306.             self.tree_view.row_activated (
  307.                 self.store.get_path (self.store.get_iter_first ()),
  308.                 self.tree_view.get_column (0))
  309.             self.store.remove (titer)
  310.             group_item.delete ()
  311.             self.emit ("items-changed")
  312.  
  313.     def get_selected_item (self):
  314.         model, titer = self.tree_view.get_selection ().get_selected ()
  315.         return model.get (titer)
  316.  
  317.     def generate_new_group_name (self):
  318.         name = _('New Group')
  319.  
  320.         if not self.store.lookup_by_name (name):
  321.             return name
  322.  
  323.         i = 1
  324.         while True:
  325.             new_name = name + ' %d' % i
  326.             if not self.store.lookup_by_name (new_name):
  327.                 return new_name
  328.             i += 1
  329.  
  330.     def _create_new_group_common (self, item):
  331.         titer = self.store.append_by_type (item)
  332.         self.emit ("items-changed")
  333.         self.tree_view.row_activated (
  334.             self.store.get_path (titer),
  335.             self.tree_view.get_column (0))
  336.         self.rename_selected_group ()
  337.  
  338.     def create_new_search_group (self, criterion, group_name = None):
  339.         item = SavedSearchGroupItem (
  340.             group_name and group_name or self.generate_new_group_name (),
  341.             criteria = [criterion])
  342.         self._create_new_group_common (item)
  343.  
  344.     def create_new_group (self, printer_queues, group_name = None):
  345.         item = StaticGroupItem (
  346.             group_name and group_name or self.generate_new_group_name ())
  347.         item.add_queues (printer_queues)
  348.         self._create_new_group_common (item)
  349.  
  350.     def on_new_group_activate (self, UNUSED):
  351.         self.create_new_group ([])
  352.  
  353.     def on_new_group_from_selection_activate (self, UNUSED):
  354.         self.create_new_group (self.currently_selected_queues)
  355.  
  356.     def is_drop_target (self, tree_view, x, y):
  357.         try:
  358.             path, position = self.tree_view.get_dest_row_at_pos (x, y)
  359.             group_item = self.store.get (path)
  360.         except TypeError:
  361.             return False
  362.  
  363.         if not isinstance (group_item, StaticGroupItem):
  364.             return False
  365.  
  366.         return True
  367.  
  368.     def on_drag_data_received (self, tree_view, context, x, y,
  369.                                selection_data, info, timestamp):
  370.         if not selection_data.data  or info != 0:
  371.             context.finish (False, False, timestamp)
  372.             return
  373.  
  374.         if not self.is_drop_target (tree_view, x, y):
  375.             context.finish (False, False, timestamp)
  376.             return
  377.  
  378.         path, position = self.tree_view.get_dest_row_at_pos (x, y)
  379.         group_item = self.store.get (path)
  380.         group_item.add_queues (selection_data.data.splitlines ())
  381.         context.finish (True, False, timestamp)
  382.  
  383.     def on_drag_drop (self, tree_view, context, x, y, timestamp):
  384.         if not self.is_drop_target (tree_view, x, y):
  385.             return False
  386.  
  387.         target_list = tree_view.drag_dest_get_target_list ()
  388.         target = tree_view.drag_dest_find_target (context, target_list)
  389.         tree_view.drag_get_data (context, target, timestamp)
  390.         return True
  391.  
  392.     def on_drag_motion (self, tree_view, context, x, y, timestamp):
  393.         if not self.is_drop_target (tree_view, x, y):
  394.             return False
  395.  
  396.         path, position = tree_view.get_dest_row_at_pos (x, y)
  397.         tree_view.set_drag_dest_row (path, position)
  398.  
  399.         context.drag_status (gtk.gdk.ACTION_COPY, timestamp)
  400.         return True
  401.  
  402.     def get_static_groups (self):
  403.         static_groups = []
  404.         for row in self.store:
  405.             if isinstance (row[0], StaticGroupItem):
  406.                 static_groups.append (row[0])
  407.         return static_groups
  408.  
  409.     def n_groups (self):
  410.         n = 0
  411.         for row in self.store:
  412.             if (isinstance (row[0], StaticGroupItem) or
  413.                 isinstance (row[0], SavedSearchGroupItem)):
  414.                     n += 1
  415.         return n
  416.  
  417. gobject.type_register (GroupsPane)
  418.